package cc.aiee.chinapay.api;

import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.fastjson.JSONObject;
import com.chinapay.secss.SecssUtil;

import cc.aiee.chinapay.config.ChinaPayConfig;
import cc.aiee.chinapay.config.ChinaPayConfigKit;
import cc.aiee.chinapay.core.enums.ChinaPayDomainEnum;
import cc.aiee.chinapay.core.enums.ChinaPayUrlEnum;
import cc.aiee.chinapay.core.tool.ChinaPayTool;
import cc.aiee.chinapay.model.ChinaPayPaymentModel;
import cc.aiee.chinapay.model.ChinaPayRefundModel;
import cc.aiee.core.bean.R;
import cc.aiee.core.interfaces.PaySandboxInterface;
import cc.aiee.core.interfaces.PayUrlInterface;
import cc.aiee.core.kit.KitHttp;
import cc.aiee.core.kit.KitSandbox;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ChinaPayApi implements PaySandboxInterface, PayUrlInterface<ChinaPayDomainEnum, ChinaPayUrlEnum> {

	private Boolean openSandBox = null;

	public R<Map<String, String>> create(ChinaPayPaymentModel model, ChinaPayConfig config) {
		if ("0".equals(model.getAccessType())) {
			model.setMerId(config.getMerchantId());
		}
		Date now = new Date();
		if (model.getTranDate() == null) {
			String format = DateUtil.format(now, DatePattern.PURE_DATE_PATTERN);
			model.setTranDate(format);
		}
		if (model.getTranTime() == null) {
			String format = DateUtil.format(now, DatePattern.PURE_TIME_PATTERN);
			model.setTranTime(format);
		}
		if (StrUtil.isBlank(model.getMerBgUrl())) {
			model.setMerBgUrl(config.getMerBgUrl());
		}

		Assert.notBlank(model.getVersion(), "Version not blank,版本号不能为空");
		Assert.notBlank(model.getMerId(), "MerId not blank,商户号不能为空");
		Assert.notBlank(model.getMerOrderNo(), "MerOrderNo  not blank,订单号不能为空");
		Assert.notBlank(model.getTranDate(), "TranDate not blank,交易日期不能为空");
		Assert.notBlank(model.getTranTime(), "TranTime not blank,交易日期不能为空");
		Assert.notBlank(model.getOrderAmt(), "OrderAmt not blank,订单金额不能为空");
		Assert.notBlank(model.getBusiType(), "BusiType not blank,业务类型不能为空");
		Assert.notBlank(model.getMerBgUrl(), "MerBgUrl  not blank,后台通知地址不能为空");
		Assert.notBlank(model.getRemoteAddr(), "RemoteAddr not blank,客服端IP不能为空");
		if (log.isDebugEnabled()) {
			log.debug("Chinapay:请求参数:\n{}", model.toJson(true, true));
		}
		return ChinaPayTool.pack(model, config);
	}

	/**
	 * 支付回调通知
	 * <li>验证签名</li>
	 * <li>解析参数 封装成Map</li>
	 * 
	 * @param request
	 * @return
	 * @author YangLong <br>
	 *         2020-09-29 19:39:09
	 */
	public R<Map<String, String>> createNotify(HttpServletRequest request) {
		R<Map<String, String>> unNotify = ChinaPayTool.unNotify(request);
		if (!unNotify.ok()) {
			return unNotify;
		}
		Map<String, String> resultMap = unNotify.getObj();
		log.info("ChinaPay Create Notify Body,ChinaPay支付回调通知:\n{}", JSONObject.toJSONString(resultMap, true));

		// 验签
		SecssUtil secssUtil = ChinaPayConfigKit.getSecssUtil();
		boolean verify = ChinaPayTool.verify(secssUtil, resultMap);

		log.info("ChinaPay Create Notify Verify Sing,ChinaPay支付回调通知验证签名:{}", verify);

		if (!verify) {
			return new R<>(secssUtil.getErrCode(), secssUtil.getErrMsg(), false);
		}

		return ChinaPayTool.unPack(secssUtil, resultMap);
	}

	public R<Map<String, String>> refundNotify(HttpServletRequest request) {
		R<Map<String, String>> unNotify = ChinaPayTool.unNotify(request);
		if (!unNotify.ok()) {
			return unNotify;
		}
		Map<String, String> resultMap = unNotify.getObj();
		log.info("ChinaPay Refund Notify Body,ChinaPay退款回调通知:\n{}", JSONObject.toJSONString(resultMap, true));

		// 验签
		SecssUtil secssUtil = ChinaPayConfigKit.getSecssUtil();
		boolean verify = ChinaPayTool.verify(secssUtil, resultMap);

		log.info("ChinaPay Refund Notify Verify Sing,ChinaPay退款回调通知验证签名:{}", verify);

		if (!verify) {
			return new R<>(secssUtil.getErrCode(), secssUtil.getErrMsg(), false);
		}

		return ChinaPayTool.unPack(secssUtil, resultMap);
	}

	public R<Map<String, String>> refund(ChinaPayRefundModel model, ChinaPayConfig config) {
		if ("0".equals(model.getAccessType())) {
			model.setMerId(config.getMerchantId());
		}
		Date now = new Date();
		if (model.getTranDate() == null) {
			String format = DateUtil.format(now, DatePattern.PURE_DATE_PATTERN);
			model.setTranDate(format);
		}
		if (model.getTranTime() == null) {
			String format = DateUtil.format(now, DatePattern.PURE_TIME_PATTERN);
			model.setTranTime(format);
		}
		// 设置退款通知地址
		if (StrUtil.isBlank(model.getMerBgUrl())) {
			model.setMerBgUrl(config.getMerBgRefundUrl());
		}

		this.openSandBox(KitSandbox.sandbox(this.openSandBox, config));

		Assert.notBlank(model.getVersion(), "Version not blank,版本号不能为空");
		Assert.notBlank(model.getMerId(), "MerId not blank,商户号不能为空");
		Assert.notBlank(model.getMerOrderNo(), "MerOrderNo  not blank,订单号不能为空");
		Assert.notBlank(model.getTranDate(), "TranDate not blank,交易日期不能为空");
		Assert.notBlank(model.getTranTime(), "TranTime not blank,交易日期不能为空");
		Assert.notBlank(model.getOriOrderNo(), "OriOrderNo not blank,原始订单号不能为空");
		Assert.notBlank(model.getOriTranDate(), "OriTranDate not blank,原始商户交易日期不能为空");
		Assert.notBlank(model.getRefundAmt(), "RefundAmt not blank,退款金额不能为空");
		Assert.notBlank(model.getTranType(), "TranType not blank,交易类型不能为空");
		Assert.notBlank(model.getBusiType(), "BusiType not blank,业务类型不能为空");
		R<Map<String, String>> pack = ChinaPayTool.pack(model, config);
		if (!pack.ok()) {
			return pack;
		}
		Map<String, String> paramMap = pack.getObj();

		String reqUrl = getReqUrl(ChinaPayUrlEnum.refund_bg);
		String result = KitHttp.post(reqUrl, paramMap);

		if (log.isDebugEnabled()) {
			log.debug("ChinaPay refund result,ChinaPay退款请求地址:\n{} \n请求参数:\n{}", reqUrl,
					JSONObject.toJSONString(paramMap, true));
		}
		log.info("ChinaPay refund result,ChinaPay原始订单号:{},退款响应结果:\n{}", model.getOriOrderNo(), result);

		String transType = paramMap.get("TranType");

		Map<String, String> unSendSyncResponseStr = ChinaPayTool.unSendSyncResponseStr(result, transType);
		SecssUtil secssUtil = ChinaPayConfigKit.getSecssUtil(config);
		return ChinaPayTool.unPack(secssUtil, unSendSyncResponseStr);
	}

	@Override
	public void openSandBox(Boolean isOpenSandBox) {
		openSandBox = isOpenSandBox;
	}

	@Override
	public String getReqUrl(ChinaPayDomainEnum domain, ChinaPayUrlEnum uri) {
		return domain.getDomain() + uri.getUrl();
	}

	@Override
	public String getReqUrl(ChinaPayUrlEnum uri) {
		ChinaPayDomainEnum domain = ChinaPayDomainEnum.PRODUCTION;
		if (openSandBox != null && openSandBox) {
			domain = ChinaPayDomainEnum.TEST;
		}
		return this.getReqUrl(domain, uri);
	}

}
